package com.ssyt.ssh.common;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.query.Query;
import org.springframework.beans.factory.annotation.Autowired;

import com.ssyt.ssh.common.util.ValidateUtil;

/**
 * 公共Dao,数据持久操作,让所有dao继承
 * 
 * @author lwj
 *
 *         2016年12月11日
 */
@SuppressWarnings("unchecked")
public class BaseDao<T, P extends Serializable> {
	@Autowired
	private SessionFactory sessionFactory;
	private Class<T> entityClass;

	public BaseDao() {
		// 通过泛型得到class对象
		ParameterizedType parameterizedType = (ParameterizedType) getClass()
				.getGenericSuperclass();
		Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
		entityClass = (Class<T>) actualTypeArguments[0];
	}

	/**
	 * 获取session
	 * 
	 * @return
	 */
	public Session getSession() {
		return sessionFactory.openSession();
	}

	/**
	 * 新增
	 * 
	 * @param t
	 * @return 当前新增主键
	 */
	protected P save(T t) {
		ValidateUtil.notNull(t, "BaseDao.save()方法参数t不能为空:" + t);
		return (P) getSession().save(t);
	}

	/**
	 * 删除
	 * 
	 * @param t
	 * 
	 */
	protected void delete(T t) {
		ValidateUtil.notNull(t, "BaseDao.delete()方法参数t不能为空:" + t);
		getSession().delete(t);
	}

	/**
	 * 修改
	 * 
	 * @param t
	 * 
	 */
	protected void update(T t) {
		ValidateUtil.notNull(t, "BaseDao.update()方法参数t不能为空:" + t);
		getSession().update(t);
	}

	/**
	 * get查询
	 * 
	 * @param t
	 * @return
	 * 
	 */
	protected T get(P p) {
		ValidateUtil.notNull(p, "BaseDao.get()方法参数p不能为空:" + p);
		return (T) getSession().get(entityClass, p);
	}

	/**
	 * load查询
	 * 
	 * @param t
	 * @return
	 * 
	 */
	protected T load(P p) {
		ValidateUtil.notNull(p, "BaseDao.load()方法参数p不能为空:" + p);
		return (T) getSession().get(entityClass, p);
	}

	/**
	 * 根据HQL查询得到单个结果（查询所有属性，如：FROM User）
	 * 
	 * @param hql
	 * @param paramList
	 * @return
	 */
	protected T uniqueEntityByHql(String hql, List<Object> paramList) {
		ValidateUtil.notBlank(hql, "BaseDao.uniqueEntityByHql()方法参数hql不能为空："
				+ hql);

		Query<T> query = getSession().createQuery(hql, entityClass);
		setParameterByHql(query, paramList);

		return query.setMaxResults(1).getSingleResult();
	}

	protected T uniqueEntityByHql(String hql, Object... params) {
		return uniqueEntityByHql(hql, Arrays.asList(params));
	}

	/**
	 * 根据HQL查询得到单个结果（查询单属性，如：SELECT username FROM User）
	 * 
	 * @param hql
	 * @param paramList
	 * @return
	 */
	protected <E> E uniqueSinglePropertyByHql(Class<E> e, String hql,
			List<Object> paramList) {
		ValidateUtil.notBlank(hql, "参数hql不能为空：" + hql);

		Query<E> query = getSession().createQuery(hql, e);
		setParameterByHql(query, paramList);

		return query.setMaxResults(1).getSingleResult();
	}

	protected <E> E uniqueSinglePropertyByHql(Class<E> e, String hql,
			Object... params) {
		return uniqueSinglePropertyByHql(e, hql, Arrays.asList(params));
	}

	/**
	 * 根据HQL查询得到单个结果（查询多属性，如：SELECT username, password FROM User || FROM User u,
	 * Log l WHERE u.id=l.user_id）
	 * 
	 * @param hql
	 * @param paramList
	 * @return
	 */
	protected Object[] uniqueMultiPropertyByHql(String hql,
			List<Object> paramList) {
		ValidateUtil.notBlank(hql, "参数hql不能为空：" + hql);

		Query<Object[]> query = getSession().createQuery(hql, Object[].class);
		setParameterByHql(query, paramList);

		return query.setMaxResults(1).getSingleResult();
	}

	protected Object[] uniqueMultiPropertyByHql(String hql, Object... params) {
		return uniqueMultiPropertyByHql(hql, Arrays.asList(params));
	}

	/**
	 * 根据HQL查询得到多个结果（如：FROM User）
	 * 
	 * @param hql
	 * @param paramList
	 * @return
	 */
	protected List<T> listEntityByHql(String hql, List<Object> paramList) {
		ValidateUtil.notBlank(hql, "参数hql不能为空：" + hql);

		Query<T> query = getSession().createQuery(hql, entityClass);
		setParameterByHql(query, paramList);
		return query.getResultList();
	}

	protected List<T> listEntityByHql(String hql, Object... params) {
		return listEntityByHql(hql, Arrays.asList(params));
	}

	
	/**
	 * 根据HQL查询得到多个结果（查询单属性，如：SELECT username FROM User）
	 * 
	 * @param hql
	 * @param paramList
	 * @return
	 */
	protected <E> List<E> listSinglePropertyByHql(Class<E> e, String hql,
			List<Object> paramList) {
		ValidateUtil.notBlank(hql, "参数hql不能为空：" + hql);

		Query<E> query = getSession().createQuery(hql, e);
		setParameterByHql(query, paramList);

		return query.getResultList();
	}

	protected <E> List<E> listSinglePropertyByHql(Class<E> e, String hql,
			Object... params) {
		return listSinglePropertyByHql(e, hql, Arrays.asList(params));
	}

	
	/**
	 * 根据HQL查询得到多个结果（查询多属性，如：SELECT username, password FROM User || FROM User u,
	 * Log l WHERE u.id=l.user_id）
	 * 
	 * @param hql
	 * @param paramList
	 * @return
	 */
	protected List<Object[]> listMultiPropertyByHql(String hql,
			List<Object> paramList) {
		ValidateUtil.notBlank(hql, "参数hql不能为空：" + hql);

		Query<Object[]> query = getSession().createQuery(hql, Object[].class);
		setParameterByHql(query, paramList);

		return query.getResultList();
	}

	protected List<Object[]> listMultiPropertyByHql(String hql,
			Object... params) {
		return listMultiPropertyByHql(hql, Arrays.asList(params));
	}

	
	/**
	 * 根据SQL查询得到单个结果（查询所有属性，如：SELECT * FROM user）
	 * 
	 * @param sql
	 * @param paramList
	 * @return
	 */
	protected T uniqueEntityBySql(String sql, List<Object> paramList) {
		ValidateUtil.notBlank(sql, "BaseDao.uniqueEntityByHql()方法参数hql不能为空："
				+ sql);

		Query<T> query = getSession().createNativeQuery(sql, entityClass);
		setParameterBySql(query, paramList);

		return query.setMaxResults(1).getSingleResult();
	}

	protected T uniqueEntityBySql(String sql, Object... params) {
		return uniqueEntityBySql(sql, Arrays.asList(params));
	}

	
	/**
	 * 根据SQL查询得到单个结果（查询单属性，如：SELECT username FROM user）
	 * 
	 * @param sql
	 * @param paramList
	 * @return
	 */
	protected <E> E uniqueSinglePropertyBySql(Class<E> e, String sql,
			List<Object> paramList) {
		ValidateUtil.notBlank(sql, "参数sql不能为空：" + sql);

		Query<E> query = getSession().createNativeQuery(sql);
		setParameterBySql(query, paramList);

		return query.setMaxResults(1).getSingleResult();
	}

	protected <E> E uniqueSinglePropertyBySql(Class<E> e, String sql,
			Object... params) {
		return uniqueSinglePropertyBySql(e, sql, Arrays.asList(params));
	}

	
	/**
	 * 根据SQL查询得到单个结果（查询多属性，如：SELECT username, password FROM user || FROM user u,
	 * Log l WHERE u.id=l.user_id）
	 * 
	 * @param sql
	 * @param paramList
	 * @return
	 */
	protected Object[] uniqueMultiPropertyBySql(String sql,
			List<Object> paramList) {
		ValidateUtil.notBlank(sql, "参数sql不能为空：" + sql);

		Query<Object[]> query = getSession().createNativeQuery(sql);
		setParameterBySql(query, paramList);

		return query.setMaxResults(1).getSingleResult();
	}

	protected Object[] uniqueMultiPropertyBySql(String sql, Object... params) {
		return uniqueMultiPropertyBySql(sql, Arrays.asList(params));
	}
	
	
	/**
	 * 根据SQL查询得到多个结果（如：FROM user）
	 * 
	 * @param sql
	 * @param paramList
	 * @return
	 */
	protected List<T> listEntityBySql(String sql, List<Object> paramList) {
		ValidateUtil.notBlank(sql, "参数sql不能为空：" + sql);

		Query<T> query = getSession().createNativeQuery(sql, entityClass);
		setParameterBySql(query, paramList);
		return query.getResultList();
	}

	protected List<T> listEntityBySql(String sql, Object... params) {
		return listEntityBySql(sql, Arrays.asList(params));
	}
	
	
	/**
	 * 根据SQL查询得到多个结果（查询单属性，如：SELECT username FROM user）
	 * 
	 * @param sql
	 * @param paramList
	 * @return
	 */
	protected <E> List<E> listSinglePropertyBySql(Class<E> e, String sql,
			List<Object> paramList) {
		ValidateUtil.notBlank(sql, "参数sql不能为空：" + sql);

		Query<E> query = getSession().createNativeQuery(sql, e);
		setParameterBySql(query, paramList);

		return query.getResultList();
	}

	protected <E> List<E> listSinglePropertyBySql(Class<E> e, String sql,
			Object... params) {
		return listSinglePropertyBySql(e, sql, Arrays.asList(params));
	}
	
	
	/**
	 * 根据SQL查询得到多个结果（查询多属性，如：SELECT username, password FROM user || FROM user u,
	 * Log l WHERE u.id=l.user_id）
	 * 
	 * @param sql
	 * @param paramList
	 * @return
	 */
	protected List<Object[]> listMultiPropertyBySql(String sql,
			List<Object> paramList) {
		ValidateUtil.notBlank(sql, "参数sql不能为空：" + sql);

		Query<Object[]> query = getSession().createNativeQuery(sql);
		setParameterBySql(query, paramList);

		return query.getResultList();
	}

	protected List<Object[]> listMultiPropertyBySql(String sql,
			Object... params) {
		return listMultiPropertyBySql(sql, Arrays.asList(params));
	}
	
	/**
	 * 根据HQL分页查询,对象
	 * @param hql
	 * @param pageNo
	 * @param pageSize
	 * @param paramList
	 * @return
	 */
	protected PageModel<T> pageEntityByHql(String hql,int pageNo,int pageSize,
			List<Object> paramList) {
		ValidateUtil.notBlank(hql, "参数hql不能为空：" + hql);
		ValidateUtil.isTrue(pageNo>0, "参数pageNo不能<=0" + pageNo);
		ValidateUtil.isTrue(pageSize>0, "参数pageSize不能<=0" + pageSize);

		Query<T> query = getSession().createQuery(hql,entityClass);
		setParameterByHql(query, paramList);
		query.setFirstResult((pageNo-1)*pageSize);
		query.setMaxResults(pageSize);
		List<T> list = query.getResultList();
		
		hql = "SELECT COUNT(*)" + hql.substring(StringUtils.indexOfIgnoreCase(hql, "FROM"));
		long totalRecords =uniqueSinglePropertyByHql(Long.class, hql, paramList);

		return new PageModel<T>(list, totalRecords, pageNo, pageSize);
	}

	protected PageModel<T> pageEntityByHql(String hql,int pageNo,int pageSize,
			Object... params) {
		return pageEntityByHql(hql,pageNo,pageSize, Arrays.asList(params));
	}
	
	/**
	 * 根据HQL分页查询,单个属性
	 * @param hql
	 * @param pageNo
	 * @param pageSize
	 * @param paramList
	 * @return
	 */
	protected PageModel<Object> pageSinglePropertyByHql(String hql,int pageNo,int pageSize,
			List<Object> paramList) {
		ValidateUtil.notBlank(hql, "参数hql不能为空：" + hql);
		ValidateUtil.isTrue(pageNo>0, "参数pageNo不能<=0" + pageNo);
		ValidateUtil.isTrue(pageSize>0, "参数pageSize不能<=0" + pageSize);

		Query<Object> query = getSession().createQuery(hql);
		setParameterByHql(query, paramList);
		query.setFirstResult((pageNo-1)*pageSize);
		query.setMaxResults(pageSize);
		List<Object> list = query.getResultList();
		
		hql = "SELECT COUNT(*)"+hql.substring(StringUtils.indexOfIgnoreCase(hql, "FROM"));
		long totalRecords =uniqueSinglePropertyByHql(Long.class, hql, paramList);

		return new PageModel<Object>(list, totalRecords, pageNo, pageSize);
	}

	protected PageModel<Object> pageSinglePropertyByHql(String hql,int pageNo,int pageSize,
			Object... params) {
		return pageSinglePropertyByHql(hql,pageNo,pageSize, Arrays.asList(params));
	}
	/**
	 * 根据HQL分页查询,多个属性
	 * @param hql
	 * @param pageNo
	 * @param pageSize
	 * @param paramList
	 * @return
	 */
	protected PageModel<Object[]> pageMultiPropertyByHql(String hql,int pageNo,int pageSize,
			List<Object> paramList) {
		ValidateUtil.notBlank(hql, "参数hql不能为空：" + hql);
		ValidateUtil.isTrue(pageNo>0, "参数pageNo不能<=0" + pageNo);
		ValidateUtil.isTrue(pageSize>0, "参数pageSize不能<=0" + pageSize);

		Query<Object[]> query = getSession().createQuery(hql);
		setParameterByHql(query, paramList);
		query.setFirstResult((pageNo-1)*pageSize);
		query.setMaxResults(pageSize);
		List<Object[]> list = query.getResultList();
		
		hql = "SELECT COUNT(*)"+hql.substring(StringUtils.indexOfIgnoreCase(hql, "FROM"));
		long totalRecords =uniqueSinglePropertyByHql(Long.class, hql, paramList);

		return new PageModel<Object[]>(list, totalRecords, pageNo, pageSize);
	}

	protected PageModel<Object[]> pageMultiPropertyByHql(String hql,int pageNo,int pageSize,
			Object... params) {
		return pageMultiPropertyByHql(hql,pageNo,pageSize, Arrays.asList(params));
	}
	
	/**
	 * 根据SQL分页查询,对象
	 * @param sql
	 * @param pageNo
	 * @param pageSize
	 * @param paramList
	 * @return
	 */
	protected PageModel<T> pageEntityBySql(String sql,int pageNo,int pageSize,
			List<Object> paramList) {
		ValidateUtil.notBlank(sql, "参数sql不能为空：" + sql);
		ValidateUtil.isTrue(pageNo>0, "参数pageNo不能<=0" + pageNo);
		ValidateUtil.isTrue(pageSize>0, "参数pageSize不能<=0" + pageSize);

		Query<T> query = getSession().createNativeQuery(sql,entityClass);
		setParameterBySql(query, paramList);
		query.setFirstResult((pageNo-1)*pageSize);
		query.setMaxResults(pageSize);
		List<T> list = query.getResultList();
		
		sql = "SELECT COUNT(*)"+sql.substring(StringUtils.indexOfIgnoreCase(sql, "FROM"));
		long totalRecords =uniqueSinglePropertyBySql(Long.class, sql, paramList);

		return new PageModel<T>(list, totalRecords, pageNo, pageSize);
	}

	protected PageModel<T> pageEntityBySql(String sql,int pageNo,int pageSize,
			Object... params) {
		return pageEntityBySql(sql,pageNo,pageSize, Arrays.asList(params));
	}
	
	/**
	 * 根据SQL分页查询,单个属性
	 * @param sql
	 * @param pageNo
	 * @param pageSize
	 * @param paramList
	 * @return
	 */
	protected PageModel<Object> pageSinglePropertyBySql(String sql,int pageNo,int pageSize,
			List<Object> paramList) {
		ValidateUtil.notBlank(sql, "参数sql不能为空：" + sql);
		ValidateUtil.isTrue(pageNo>0, "参数pageNo不能<=0" + pageNo);
		ValidateUtil.isTrue(pageSize>0, "参数pageSize不能<=0" + pageSize);

		Query<Object> query = getSession().createNativeQuery(sql);
		setParameterBySql(query, paramList);
		query.setFirstResult((pageNo-1)*pageSize);
		query.setMaxResults(pageSize);
		List<Object> list = query.getResultList();
		
		sql = "SELECT COUNT(*)"+sql.substring(StringUtils.indexOfIgnoreCase(sql, "FROM"));
		long totalRecords =uniqueSinglePropertyBySql(Long.class, sql, paramList);

		return new PageModel<Object>(list, totalRecords, pageNo, pageSize);
	}

	protected PageModel<Object> pageSinglePropertyBySql(String sql,int pageNo,int pageSize,
			Object... params) {
		return pageSinglePropertyBySql(sql, pageNo,pageSize,Arrays.asList(params));
	}
	/**
	 * 根据SQL分页查询,多个属性
	 * @param sql
	 * @param pageNo
	 * @param pageSize
	 * @param paramList
	 * @return
	 */
	protected PageModel<Object[]> pageMultiPropertyBySql(String sql,int pageNo,int pageSize,
			List<Object> paramList) {
		ValidateUtil.notBlank(sql, "参数sql不能为空：" + sql);
		ValidateUtil.isTrue(pageNo>0, "参数pageNo不能<=0" + pageNo);
		ValidateUtil.isTrue(pageSize>0, "参数pageSize不能<=0" + pageSize);

		Query<Object[]> query = getSession().createNativeQuery(sql);
		setParameterBySql(query, paramList);
		query.setFirstResult((pageNo-1)*pageSize);
		query.setMaxResults(pageSize);
		List<Object[]> list = query.getResultList();
		
		sql = "SELECT COUNT(*)"+sql.substring(StringUtils.indexOfIgnoreCase(sql, "FROM"));
		long totalRecords =uniqueSinglePropertyBySql(Long.class, sql, paramList);

		return new PageModel<Object[]>(list, totalRecords, pageNo, pageSize);
	}

	protected PageModel<Object[]> pageMultiPropertyBySql(String sql,int pageNo,int pageSize,
			Object... params) {
		return pageMultiPropertyBySql(sql,pageNo,pageSize, Arrays.asList(params));
	}
	/**
	 * Query 参数设置
	 * 
	 * @param query
	 * @param paramList
	 */
	public void setParameterByHql(Query<?> query, List<Object> paramList) {
		if (paramList != null && !paramList.isEmpty()) {
			for (int i = 0; i < paramList.size(); i++) {
				query.setParameter(i, paramList.get(i));
			}
		}
	}

	public void setParameterBySql(Query<?> query, List<Object> paramList) {
		if (paramList != null && !paramList.isEmpty()) {
			for (int i = 0; i < paramList.size(); i++) {
				query.setParameter(i+1, paramList.get(i));
			}
		}
	}
}
